package com.mixsmart.web.tag;

import java.io.IOException;
import java.util.List;

import javax.servlet.jsp.JspException;
import javax.servlet.jsp.JspWriter;

import com.mixsmart.commonweb.bean.UserInfo;
import com.mixsmart.commonweb.service.IOPAuthService;
import com.mixsmart.commonweb.utils.SpringContextUtils;
import com.mixsmart.core.bean.MixResponse;
import com.mixsmart.utils.StringUtils;
import com.mixsmart.web.tag.bean.CustomBtn;
import com.mixsmart.web.tag.bean.DelBtn;
import com.mixsmart.web.tag.bean.EditBtn;
import com.mixsmart.web.tag.bean.PageParam;
import com.mixsmart.web.tag.bean.RefreshBtn;
import com.mixsmart.web.tag.enums.BtnPropType;

/**
 * 自定义表格标签
 * @author lmq <br />
 * 2016年8月2日
 * @version 1.0
 * @since JDK1.6
 */
public class TableTag extends BaseTag {

	private static final long serialVersionUID = 1938463689212817558L;

	//表格头数据,多个之间用英文逗号隔开
	protected String headers;
	//表格单元格宽度,多个之间用英文逗号隔开
	protected String headerWidths;
	
	//表格单元格样式,多个之间用英文逗号隔开
	protected String stylesClass;
	
	//数据中是否包含ID
    protected int isId = 1;
	
	//id是否显示
    protected int isIdShow = 0;
    
    /**
     * 表格ID 
     */
    protected String tableId;
	
    /**
     * 计算高度时需要减去的高度
     */
	protected Integer subtractHeight = 0;
    
    /**
     * 如果为null时，不限制高度，即auto
     * 如果为小于1时，则自动限制高度
     * 如果大于1时，则使用自定义的高度
     */
    protected int limitHeight = 0;
	
	//是否有复选框
    protected int isCheckbox = 0;
    
    /**
     * 是否支持行选中
     * 1--支持
     * 0--不支持
     */
    protected int isRowSelected = 0;
    
    //是否分页
    protected PageParam page;
	
	//是否有添加按钮
    protected EditBtn addBtn;
	
	//编辑按钮
    protected EditBtn editBtn;
	
	//删除按钮
    protected DelBtn delBtn;
    
    protected List<ALink> alinks;
	
	//刷新按钮
    protected RefreshBtn refreshBtn;
    
    protected List<CustomBtn> customBtns;
    
    protected MixResponse<Object> mixResp;
    
    @Override
	public int doEndTag() throws JspException {
		return EVAL_PAGE;
	}

	@Override
	public int doStartTag() throws JspException {
		try {
			JspWriter out = this.pageContext.getOut();
			printTableBody(out);
			printFooter(out);
		} catch (Exception e) {
			throw new JspException(e.getMessage());
		}
		return SKIP_BODY;
	}

	@Override
	public void release() {
		super.release();
		refreshBtn = null;
		delBtn = null;
		editBtn = null;
		addBtn = null;
		page = null;
		mixResp = null;
	}
    
	/**
	 * 生成表格
	 * @param out JSP输出对象
	 * @param divTag 页面标识符(div名称)
	 * @param tableStyles 表格样式
	 * @param isTree 是否为树，可选值为：true或false
	 */
	protected void printTable(JspWriter out,String divTag,String tableStyles,boolean isTree) {
		try {
			if(limitHeight == 0) {
	    		out.println("<div>");
	    	} else {
	    		try {
	    			int height = limitHeight;
	    			if(height < 1) {
	    				out.println("<div class='cnoj-table-wrap table-wrap-limit' data-subtract-height='"+this.subtractHeight+"'>");
	    			} else {
	    				out.println("<div class='table-wrap-limit' data-subtract-height='"+this.subtractHeight+"' style='height:"+limitHeight+"px'>");
	    			}
	    		} catch (Exception e) {
	    			out.println("<div>");
				}
	    	}
	    	String tableClassStyle = "";
	    	if(!isTree)
	    		tableClassStyle = "table-striped";
	    	else 
	    		tableClassStyle = "table-hover";
	    	if(null == tableStyles) {
	    		tableStyles = "table-bordered table-condensed";
	    	} else {
	    		tableClassStyle = "";
	    	}
	    	out.println("<table "+(StringUtils.isNotEmpty(this.tableId)?"id='"+this.tableId+"'":"")+" class='table "+tableClassStyle+" "+tableStyles+" "+StringUtils.handNull(divTag)+" "+(isCheckbox==1?"cnoj-checkbox-wrap":"")+" '>");
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
   /**
    * 生成表格头
    * @param out JSP输出对象
    * @param divTag 页面标识符(div名称)
    * @param tableStyles　表格样式
    * @param isTree 是否为树，可选值为：true或false
    * @param headerTrStyle 表格标题行样式
    * @return 返回表格标题行中各列的宽
    */
    protected String[] printTableHeader(JspWriter out,String divTag,String tableStyles,boolean isTree,String headerTrStyle) {
    	String[] tWidth = null;
    	try {
    		printTable(out, divTag, tableStyles, isTree);
	    	if(StringUtils.isEmpty(headers)) {
	    		log.info("没有表格标头！");
	    	}
	    	String[] tdStyles = null;
	    	String[] headerArray = null;
	    	int cols = 0;
	    	if(StringUtils.isEmpty(headerTrStyle)) {
	    		headerTrStyle = "ui-state-default";
	    	}
	    	if(!StringUtils.isEmpty(headers)) {
	    		out.println("<thead><tr class='"+headerTrStyle+"' data-height='36'>");
	    		if(isCheckbox==1) {
		    		out.println("<th class='th-checkbox text-center'><div class='checkbox'><label><input class='cnoj-checkbox-all cnoj-op-checkbox' data-target='.one-checkbox' value='' type='checkbox'></label></div></th>");
		    	}
	    		headerArray = headers.split(",");
		    	tWidth = new String[headerArray.length];
		    	cols = headerArray.length;
		    	if(StringUtils.isEmpty(stylesClass)) {
		    		stylesClass = "text-left";
		    	}
		    	if(!StringUtils.isEmpty(stylesClass)) {
		    		tdStyles = stylesClass.split(",");
		    		if(tdStyles.length==1) {
		    			tdStyles = new String[cols];
		    			for (int i = 0; i < tdStyles.length; i++) {
		    				tdStyles[i] = stylesClass;
						}
		    		}
		    	}
		    	if(!StringUtils.isEmpty(headerWidths)) {
		    		String[] headerWidthArray = headerWidths.split(",");
		    		if(headerWidthArray.length==headerArray.length) {
		    			for (int i = 0; i < headerArray.length; i++) {
							out.println("<th class='"+tdStyles[i]+"' style='width:"+headerWidthArray[i]+"'>"+headerArray[i]+"</th>");
							tWidth[i] = headerWidthArray[i];
						}
		    		}
		    	} else {
	    			int w = (int)Math.round(100/headerArray.length);
	    			for (int i = 0; i < headerArray.length; i++) {
	    					out.println("<th class='"+tdStyles[i]+"' style='width:"+w+"%'>"+headerArray[i]+"</th>");
	    					tWidth[i] = w+"%";
	    			}
		    	}
		    	out.println("</tr></thead>");
	    	} 
	    	
    	} catch (IOException e) {
			e.printStackTrace();
		}
    	return tWidth;
    }
    
    /**
     * 生成表格内容
     * @param out JSP输出对象
     */
	protected void printTableBody(JspWriter out) {
    	String[] thWidth = printTableHeader(out,"cnoj-table",null,false,null);
    	String[] tdStyles = null;
    	int cols = headers.split(",").length;
    	if(!StringUtils.isEmpty(stylesClass)) {
    		tdStyles = stylesClass.split(",");
    		if(tdStyles.length==1) {
    			tdStyles = new String[cols];
    			for (int i = 0; i < tdStyles.length; i++) {
    				tdStyles[i] = stylesClass;
				}
    		}
    	}
    	if(null != thWidth) {
    		try {
    			out.println("<tbody>");
	    		if(!OP_SUCCESS.equals(mixResp.getResult())) {
	    			if(isCheckbox==1) {
	    				cols++;
	    			}
	    			out.println("<tr><td colspan='"+cols+"' class='text-center'>"+mixResp.getMsg()+"</td></tr>");
	    		} else {
	    			List<Object> objs = mixResp.getDatas();
	    			for (Object obj : objs) {
						Object[] objArray = (Object[])obj;
						if(isRowSelected==1 && isCheckbox==1) {
							out.println("<tr id='t-"+StringUtils.handNull(objArray[0])+"' class='tr-selected tr-mutil-selected'>");
						} else if(isRowSelected == 1 && isCheckbox==0){
							out.println("<tr id='t-"+StringUtils.handNull(objArray[0])+"' class='tr-selected tr-one-selected'>");
						} else {
							out.println("<tr id='t-"+StringUtils.handNull(objArray[0])+"'>");
						}
						if(isCheckbox==1) {
							out.println("<td class='td-checkbox text-center'><div class='checkbox'><label><input type='checkbox' class='one-checkbox cnoj-op-checkbox' value='"+StringUtils.handNull(objArray[0])+"'></label></div></td>");
						}
						int count = 0;
						for (int i = 0; i < objArray.length;i++) {
							String tdStyle = "";
							if(null != tdStyles) {
								tdStyle = tdStyles[count];
							}
							if(isId==1 && isIdShow==1) {
								out.println("<td "+(StringUtils.isEmpty(tdStyle)?"":"class='"+tdStyle+"'")+" style='width:"+thWidth[count]+"'>"+StringUtils.handNull(objArray[0])+"</td>");
								count++;
								if(null != tdStyles) {
									tdStyle = tdStyles[count];
								}
							} else {
								if(i==0)
								   continue;
							}
							String widthStyle = "";
							if(!StringUtils.isEmpty(thWidth[count])) {
								widthStyle = "style='width:"+thWidth[count]+"'";
							}
							String a = null;
							if(null != alinks && alinks.size()>0) {
								for (ALink alink : alinks) {
									int postion = Integer.parseInt(alink.getLinkPostion());
									if(count == postion) {
										a = getALinkContent(alink, objArray);
										a = "<a "+a+">"+StringUtils.handNull(objArray[i])+"</a>";
										break;
									}
								}
							}
							if(StringUtils.isEmpty(a)) {
								a = StringUtils.handNull(objArray[i]);
							}
							out.println("<td "+(StringUtils.isEmpty(tdStyle)?"":"class='"+tdStyle+"'")+" "+widthStyle+">"+a+"</td>");
							count++;
						}
						out.println("</tr>");
					}
	    		}
	    		out.println("</tbody></table></div>");
    		} catch (Exception e) {
				e.printStackTrace();
			}
    	}
    }
    
    
    /**
     * 获取超链接中的uri（组合参数）
     * @param alink ａ链接对象
     * @param objArray 参数数组
     * @return 返回链接组合结果
     */
    protected String getALinkUriParam(ALink alink,Object[] objArray) {
    	StringBuilder paramBuilder = new StringBuilder();
    	String[] paramNameArray = alink.getParamName().split(",");
		String[] paramIndexArray = alink.getParamIndex().split(",");
		for (int j = 0; j < paramNameArray.length; j++) {
			paramBuilder.append(paramNameArray[j]+"=");
			if(paramIndexArray[j].startsWith("'") && paramIndexArray[j].endsWith("'")) {
				paramBuilder.append(paramIndexArray[j].substring(1,paramIndexArray[j].length()-1));
			} else {
				paramBuilder.append(objArray[Integer.parseInt(paramIndexArray[j].trim())]);
			}
			paramBuilder.append("&");
		}
		if(paramBuilder.length()>0) {
			paramBuilder = paramBuilder.delete(paramBuilder.length()-1, paramBuilder.length());
		}
    	return paramBuilder.toString();
    }
    
    /**
     * 获取超链接(组合链接)
     * @param alink　ａ链接对象
     * @param objArray　参数数组
     * @return　返回链接组合结果
     */
    protected String getALinkContent(ALink alink,Object[] objArray) {
    	String a = "";
    	String uri = alink.getUri();
		if(uri.indexOf("?")>0) {
			uri = uri+"&"+getALinkUriParam(alink, objArray);
		} else {
			uri = uri+"?"+getALinkUriParam(alink, objArray);
		}
    	if(StringUtils.isEmpty(alink.getaTarget())) {
			a = " href='#' class='"+alink.getClassTarget()+"' title='"+alink.getDialogTitle()+"' data-uri='"+uri+"' data-width='"+alink.getDialogWith()+"' data-title='"+alink.getDialogTitle()+"'";
		} else {
			a = " href='"+uri+"' title='"+alink.getDialogTitle()+"' target='"+alink.getaTarget()+"'";
		}
    	return a;
    }
    
    /**
     * 生成表尾（如：按钮，分页等信息）
     * @param out JSP输出对象
     */
    protected void printFooter(JspWriter out) {
    	try {
    		UserInfo userInfo = getUserInfo();
    		IOPAuthService authServ = SpringContextUtils.find(IOPAuthService.class);
    		out.println("<div class='panel-footer ui-state-default panel-footer-page' data-height='34'>");
    		if(null != addBtn || null != editBtn || null != delBtn || null != refreshBtn 
    				|| (null != customBtns && customBtns.size()>0)) {
    			out.println("<div class='btn-list'><div class='btn-group btn-group-sm cnoj-op-btn-list'>");
    			if(null != addBtn && authServ.isAuth(currentUri, addBtn.getId(), userInfo.getRoleIds())) {
    				if(StringUtils.isEmpty(addBtn.getSelectedType()))
    					addBtn.setSelectedType(BtnPropType.SelectType.NONE.getValue());
    				out.println("<button type='button' id='"+addBtn.getId()+"' class='btn "+(StringUtils.isEmpty(addBtn.getBtnStyle())?BTN_DEFAULT_THEME:addBtn.getBtnStyle())+" add param' data-selected-type='"+StringUtils.handNull(addBtn.getSelectedType())+"' data-uri='"+StringUtils.handNull(addBtn.getUri())+"' data-title='"+StringUtils.handNull(addBtn.getTitle())+"' data-value='' data-width='"+(addBtn.getWidth() == 0?POP_WIN_WIDTH:addBtn.getWidth())+"' ><i class='glyphicon glyphicon-plus'></i> "+(StringUtils.isEmpty(addBtn.getName())?"添加":addBtn.getName())+"</button>");
    			}
    			if(null != editBtn && authServ.isAuth(currentUri, editBtn.getId(), userInfo.getRoleIds())) {
    				if(StringUtils.isEmpty(editBtn.getSelectedType()))
    					editBtn.setSelectedType(BtnPropType.SelectType.MULTI.getValue());
    				out.println("<button type='button' id='"+editBtn.getId()+"' class='btn "+(StringUtils.isEmpty(editBtn.getBtnStyle())?BTN_DEFAULT_THEME:editBtn.getBtnStyle())+" edit param' data-selected-type='"+StringUtils.handNull(editBtn.getSelectedType())+"' data-uri='"+StringUtils.handNull(editBtn.getUri())+"' data-title='"+StringUtils.handNull(editBtn.getTitle())+"' data-value='' data-width='"+(editBtn.getWidth() == 0?POP_WIN_WIDTH:editBtn.getWidth())+"' ><i class='glyphicon glyphicon-pencil'></i> "+(StringUtils.isEmpty(editBtn.getName())?"编辑":editBtn.getName())+"</button>");
    			}
    			if(null != delBtn && authServ.isAuth(currentUri, delBtn.getId(), userInfo.getRoleIds())) {
    				if(StringUtils.isEmpty(delBtn.getSelectedType()))
    					delBtn.setSelectedType(BtnPropType.SelectType.MULTI.getValue());
    				out.println("<button type='button' id='"+delBtn.getId()+"' class='btn "+(StringUtils.isEmpty(delBtn.getBtnStyle())?BTN_DEFAULT_THEME:delBtn.getBtnStyle())+" del param' data-selected-type='"+StringUtils.handNull(delBtn.getSelectedType())+"' data-uri='"+StringUtils.handNull(delBtn.getUri())+"' data-msg='"+StringUtils.handNull(delBtn.getMsg())+"' data-value='' data-refresh-uri='"+StringUtils.handNull(delBtn.getRefreshUri())+"' data-target='"+StringUtils.handNull(delBtn.getTarget())+"' data-delAfter='"+StringUtils.handNull(delBtn.getCallback())+"' ><i class='glyphicon glyphicon-trash'></i> "+(StringUtils.isEmpty(delBtn.getName())?"删除":delBtn.getName())+"</button>");
    			}
    			if(null != refreshBtn && authServ.isAuth(currentUri, refreshBtn.getId(), userInfo.getRoleIds())) {
    				out.println("<button type='button' id='"+refreshBtn.getId()+"' class='btn "+(StringUtils.isEmpty(refreshBtn.getBtnStyle())?BTN_DEFAULT_THEME:refreshBtn.getBtnStyle())+" refresh' data-uri='"+StringUtils.handNull(refreshBtn.getUri())+"' data-target='"+StringUtils.handNull(refreshBtn.getTarget())+"' ><i class='glyphicon glyphicon-refresh'></i> "+(StringUtils.isEmpty(refreshBtn.getName())?"刷新":refreshBtn.getName())+"</button>");
    			}
    			if(null != customBtns && customBtns.size()>0) {
    				for (CustomBtn customBtn : customBtns) {
    					if(authServ.isAuth(currentUri, customBtn.getId(), userInfo.getRoleIds())) {
	    					String icon = "";
	    					if(!StringUtils.isEmpty(customBtn.getBtnIcon())) {
	    						icon = "<i class='glyphicon "+StringUtils.handNull(customBtn.getBtnIcon())+"'></i>";
	    					}
	    					out.println("<button type='button' id='"+customBtn.getId()+"' class='btn "+StringUtils.handNull(customBtn.getBtnStyle())+" "+customBtn.getOpenStyle()+" param' data-selected-type='"+StringUtils.handNull(customBtn.getSelectedType())+"' data-uri='"+StringUtils.handNull(customBtn.getUri())+"' data-title='"+StringUtils.handNull(customBtn.getTitle())+"' data-value='' data-param-name='"+StringUtils.handNull(customBtn.getParamName())+"' data-width='"+(customBtn.getWidth()==0?POP_WIN_WIDTH:customBtn.getWidth())+"' >"+icon+" "+StringUtils.handNull(customBtn.getName())+"</button>");
	    					}
    				}
    			}
    			customBtns = null;
    			out.println("</div></div>");
    		}
    		userInfo = null;
   			authServ = null;
    		if(null != page && mixResp.getTotalPage()>1) {
    			String pageUri = page.getUri();
        		if(StringUtils.isNotEmpty(pageUri)) {
        			pageUri = pageUri.replaceAll("page=\\d+&|page=\\d+|\\?page=\\d+$", "");
            		pageUri += (StringUtils.isContains(pageUri, "?")?"&":"?")+"page=";
        		} else {
        			pageUri = "";
        		}
    			out.println("<div class='btn-page'>");
    			out.println("<div class='page'><ul class='pagination pagination-sm'><li class='"+(page.getPage()==1?"disabled":"")+"'>");
    			if(page.getPage() == 1) {
    				out.println("<a href='javascript:void(0)' class='pre-page'>&laquo;</a>");
    			} else {
    				out.println("<a data-uri='"+pageUri+(page.getPage()-1)+"' href='#' class='cnoj-change-page pre-page' data-target='"+StringUtils.handNull(page.getTarget())+"'>&laquo;</a>");
    			}
    			out.println("</li>");
    			if(mixResp.getTotalPage()>1) {
    				int showPageNum = 5;
    				int first = 1;
    				if(page.getPage()>=showPageNum) {
    					first = page.getPage()-2;
    				}
    				int last = 1;
    				if(mixResp.getTotalPage()>0) {
    					if(mixResp.getTotalPage()>showPageNum) {
    						if(page.getPage()>=showPageNum) {
    							last = page.getPage()+2;
    							last = last>mixResp.getTotalPage()?mixResp.getTotalPage():last;
    						} else {
    						   last = showPageNum;	
    						}
    					} else {
    						last = mixResp.getTotalPage();
    					}
    				}
    				if(mixResp.getTotalPage()>showPageNum)
    					first = (last-first)<(showPageNum-1)?(last-showPageNum+1):first;
    				
    				for (int i = first; i <= last; i++) {
						out.println("<li class='"+(page.getPage()==i?"active":"")+"'><a class='cnoj-change-page' data-uri='"+pageUri+i+"' href='#' data-target='"+StringUtils.handNull(page.getTarget())+"'>"+i+"</a></li>");
					}
    			}
    			out.println("<li class='"+(page.getPage()>=mixResp.getTotalPage()?"disabled":"")+"'>");
    			if(page.getPage()>=mixResp.getTotalPage()) {
    				out.println("<a href='javascript:void(0)' class='next-page'>&raquo;</a>");
    			} else {
    				out.println("<a href='#' data-uri='"+pageUri+(page.getPage()+1)+"' class='cnoj-change-page next-page' data-target='"+StringUtils.handNull(page.getTarget())+"'>&raquo;</a>");
    			}
    			out.println("</li>");
    			out.println("<li>&nbsp;到<input class='form-control input-sm goto-page-input' name='page' value='' />页<button data-uri='"+pageUri+"' class='btn btn-default btn-xs cnoj-goto-page' data-target='"+StringUtils.handNull(page.getTarget())+"'>确定</button></li>");
    			out.println("</ul>");
    			out.println("</div>");
    			out.println("</div>");
    		}
    		
    		out.println("<div class='page-info'>");
    		if(null != page) {
    			out.println("<span>"+(mixResp.getTotalPage()>0?page.getPage():"0")+" - "+mixResp.getTotalPage()+"</span>");
    		}
    		out.println("<span>&nbsp;&nbsp; 共"+mixResp.getTotalNum()+"条(每页显示"+(mixResp.getPerPageSize()==0?mixResp.getTotalNum():mixResp.getPerPageSize())+"条)</span></div>");
    		out.println("</div>");
    	} catch (Exception e) {
			e.printStackTrace();
		}
    }

    
    
    ////////setter and getter//////////
	public String getHeaders() {
		return headers;
	}

	public void setHeaders(String headers) {
		this.headers = headers;
	}

	public int getIsId() {
		return isId;
	}

	public void setIsId(int isId) {
		this.isId = isId;
	}

	public int getIsIdShow() {
		return isIdShow;
	}

	public void setIsIdShow(int isIdShow) {
		this.isIdShow = isIdShow;
	}

	public int getIsCheckbox() {
		return isCheckbox;
	}

	public void setIsCheckbox(int isCheckbox) {
		this.isCheckbox = isCheckbox;
	}

	public PageParam getPage() {
		return page;
	}

	public void setPage(PageParam page) {
		this.page = page;
	}

	public EditBtn getAddBtn() {
		return addBtn;
	}

	public void setAddBtn(EditBtn addBtn) {
		this.addBtn = addBtn;
	}

	public EditBtn getEditBtn() {
		return editBtn;
	}

	public void setEditBtn(EditBtn editBtn) {
		this.editBtn = editBtn;
	}

	public DelBtn getDelBtn() {
		return delBtn;
	}

	public void setDelBtn(DelBtn delBtn) {
		this.delBtn = delBtn;
	}

	public RefreshBtn getRefreshBtn() {
		return refreshBtn;
	}

	public void setRefreshBtn(RefreshBtn refreshBtn) {
		this.refreshBtn = refreshBtn;
	}

	public String getHeaderWidths() {
		return headerWidths;
	}

	public void setHeaderWidths(String headerWidths) {
		this.headerWidths = headerWidths;
	}

	public int getLimitHeight() {
		return limitHeight;
	}

	public void setLimitHeight(int limitHeight) {
		this.limitHeight = limitHeight;
	}

	public List<CustomBtn> getCustomBtns() {
		return customBtns;
	}

	public void setCustomBtns(List<CustomBtn> customBtns) {
		this.customBtns = customBtns;
	}

	public int getIsRowSelected() {
		return isRowSelected;
	}

	public void setIsRowSelected(int isRowSelected) {
		this.isRowSelected = isRowSelected;
	}

	public String getStylesClass() {
		return stylesClass;
	}

	public void setStylesClass(String stylesClass) {
		this.stylesClass = stylesClass;
	}

	public List<ALink> getAlinks() {
		return alinks;
	}

	public void setAlinks(List<ALink> alinks) {
		this.alinks = alinks;
	}

	public MixResponse<Object> getmixResp() {
		return mixResp;
	}

	public void setmixResp(MixResponse<Object> mixResp) {
		this.mixResp = mixResp;
	}

	public String getTableId() {
		return tableId;
	}

	public void setTableId(String tableId) {
		this.tableId = tableId;
	}

	public Integer getSubtractHeight() {
		return subtractHeight;
	}

	public void setSubtractHeight(Integer subtractHeight) {
		this.subtractHeight = subtractHeight;
	}
}
